﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static UnityEngine.Networking.UnityWebRequest;

namespace ZyGame.Execute
{
    sealed class RunnableManager : Singleton<RunnableManager>
    {
        private Dictionary<string, IRunning> runnables = new Dictionary<string, IRunning>();

        public bool TryGetOrCreate<T>(string key, out T result) where T : IRunning
        {
            if (key.IsNullOrEmpty())
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (runnables.TryGetValue(key, out IRunning running))
            {
                result = (T)running;
                return true;
            }
            running = Activator.CreateInstance<T>();
            running.name = key;
            result = (T)running;
            runnables.Add(key, running);
            Client.Console.WriteLine($"[CREATE RUNNABLE] {key}");
            return false;
        }

        public void Remove(string key)
        {
            if (key.IsNullOrEmpty())
            {
                return;
            }
            if (runnables.TryGetValue(key, out IRunning running))
            {
                running.Dispose();
                runnables.Remove(key);
                Client.Console.WriteLine($"[DISPOSE RUNNABLE] {key}");
            }
        }

        public Runnable<T> FromCompleted<T>(T args)
        {
            TryGetOrCreate<Runnable<T>>(Guid.NewGuid().ToString(), out var result);
            IEnumerator Runnable()
            {
                result.SetResult(args);
                yield return new WaitForSeconds(0.01f);
                yield return result.Waitting();
            }
            Client.Tools.StartCoroutine(Runnable());
            return result;
        }

        public Runnable<T> FromException<T>(Exception args)
        {
            TryGetOrCreate<Runnable<T>>(Guid.NewGuid().ToString(), out var result);
            IEnumerator Runnable()
            {
                result.SetResult(args);
                yield return new WaitForSeconds(0.01f);
                yield return result.Waitting();
            }
            Client.Tools.StartCoroutine(Runnable());
            return result;
        }

        public Runnable FromCompleted(object args)
        {
            TryGetOrCreate<Runnable>(Guid.NewGuid().ToString(), out var result);
            IEnumerator Runnable()
            {
                result.SetResult(args);
                yield return new WaitForSeconds(0.01f);
                yield return result.Waitting();
            }
            Client.Tools.StartCoroutine(Runnable());
            return result;
        }

        public Runnable FromCompleted(Exception args)
        {
            TryGetOrCreate<Runnable>(Guid.NewGuid().ToString(), out var result);
            IEnumerator Runnable()
            {
                result.SetResult(args);
                yield return new WaitForSeconds(0.01f);
                yield return result.Waitting();
            }
            Client.Tools.StartCoroutine(Runnable());
            return result;
        }
    }
}